package at.fhooe.stefanirndorfer.event;

import java.util.ArrayList;
import java.util.HashMap;

public class SaveListenerStrategy implements ListenerStrategy {

	private final HashMap<Class<? extends Event<?>>, ArrayList<? extends EventListener>> m_listeners;

	public SaveListenerStrategy() {
		m_listeners = new HashMap<Class<? extends Event<?>>, ArrayList<? extends EventListener>>();
	}

	@SuppressWarnings("unchecked")
	private <T extends EventListener> ArrayList<T> getListeners(
			Class<? extends Event<T>> type) {
		return (ArrayList<T>) m_listeners.get(type);
	}

	@Override
	public <T extends EventListener> void removeListener(T eventListener,
			Class<? extends Event<T>> eventType) {
		ArrayList<T> listenerList = getListeners(eventType);

		if (listenerList != null) {
			listenerList.remove(eventListener);
		}
	}

	@Override
	public <T extends EventListener> void addListener(T eventListener,
			Class<? extends Event<T>> eventType) {
		ArrayList<T> listenerList = getListeners(eventType);

		if (listenerList == null) {
			listenerList = new ArrayList<T>();
			listenerList.add(eventListener);
			m_listeners.put(eventType, listenerList);
		} else {
			if (listenerList.contains(eventListener)) {
				throw new RuntimeException("Listener already added!");
			} else {
				listenerList.add(eventListener);
			}
		}
	}

	@Override
	public <T extends EventListener> void fireEvent(Event<T> event) {
		// copy list, since listeners can be removed when state changes
		@SuppressWarnings("unchecked")
		Class<? extends Event<T>> eventType = (Class<? extends Event<T>>) event
				.getClass();
		ArrayList<T> tmpListeners = getListeners(eventType);

		if (tmpListeners != null) {
			ArrayList<T> listenersForProcessing = new ArrayList<T>(tmpListeners);

			for (T listener : listenersForProcessing) {
				event.process(listener);
			}

			listenersForProcessing.clear(); // TODO remove
		}
	}

	@Override
	public void removeAllListeners() {
		for (Class<? extends Event<?>> eventType : m_listeners.keySet()) {
			m_listeners.get(eventType).clear();
		}
		m_listeners.clear();
	}

}
